"""
视频分析器基类

定义视频分析的通用接口和基础功能。
"""

from abc import abstractmethod
from typing import List, Dict, Any, Optional, Tuple, Union
import numpy as np

from src.core.plugin import ProcessorPlugin


class VideoAnalyzer(ProcessorPlugin):
    """
    视频分析器抽象基类
    
    定义视频分析的标准接口。
    """
    
    @property
    def name(self) -> str:
        return self.__class__.__name__
    
    @property
    def version(self) -> str:
        return "1.0.0"
    
    @property
    def description(self) -> str:
        return "视频分析器基类"
    
    def get_supported_operations(self) -> List[str]:
        return ["analyze_video", "detect_scenes", "extract_features", "analyze_frames"]
    
    async def process(self, input_data: Any, operation: str = "analyze_video", **kwargs) -> Any:
        """
        处理视频数据
        
        Args:
            input_data: 输入数据（通常是视频文件路径）
            operation: 操作类型
            **kwargs: 其他参数
        
        Returns:
            分析结果
        """
        if operation == "analyze_video":
            return await self.analyze_video(input_data, **kwargs)
        elif operation == "detect_scenes":
            return await self.detect_scenes(input_data, **kwargs)
        elif operation == "extract_features":
            return await self.extract_features(input_data, **kwargs)
        elif operation == "analyze_frames":
            return await self.analyze_frames(input_data, **kwargs)
        else:
            raise ValueError(f"不支持的操作类型: {operation}")
    
    @abstractmethod
    async def analyze_video(self, video_path: str, **kwargs) -> Dict[str, Any]:
        """
        分析视频
        
        Args:
            video_path: 视频文件路径
            **kwargs: 其他参数
        
        Returns:
            分析结果字典
        """
        pass
    
    @abstractmethod
    async def detect_scenes(self, video_path: str, **kwargs) -> List[Dict[str, Any]]:
        """
        检测场景变化
        
        Args:
            video_path: 视频文件路径
            **kwargs: 其他参数
        
        Returns:
            场景列表
        """
        pass
    
    @abstractmethod
    async def extract_features(self, video_path: str, **kwargs) -> Dict[str, Any]:
        """
        提取视频特征
        
        Args:
            video_path: 视频文件路径
            **kwargs: 其他参数
        
        Returns:
            特征字典
        """
        pass
    
    @abstractmethod
    async def analyze_frames(self, video_path: str, **kwargs) -> List[Dict[str, Any]]:
        """
        分析视频帧
        
        Args:
            video_path: 视频文件路径
            **kwargs: 其他参数
        
        Returns:
            帧分析结果列表
        """
        pass


class FrameAnalyzer:
    """
    帧分析器基类
    
    用于分析单个视频帧。
    """
    
    def analyze_frame(self, frame: np.ndarray, frame_index: int = 0) -> Dict[str, Any]:
        """
        分析单个帧

        Args:
            frame: 视频帧（numpy数组）
            frame_index: 帧索引

        Returns:
            帧分析结果
        """
        # 基础帧分析
        result = {
            "frame_index": frame_index,
            "brightness": self.calculate_brightness(frame),
            "contrast": self.calculate_contrast(frame),
            "histogram": self.extract_histogram(frame)
        }

        # 边缘检测
        edges = self.detect_edges(frame)
        edge_density = np.sum(edges > 0) / (edges.shape[0] * edges.shape[1])
        result["edge_density"] = float(edge_density)

        return result
    
    def extract_histogram(self, frame: np.ndarray, bins: int = 256) -> Dict[str, np.ndarray]:
        """提取颜色直方图"""
        import cv2
        
        # 转换为HSV颜色空间
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        
        # 计算直方图
        hist_h = cv2.calcHist([hsv], [0], None, [bins], [0, 180])
        hist_s = cv2.calcHist([hsv], [1], None, [bins], [0, 256])
        hist_v = cv2.calcHist([hsv], [2], None, [bins], [0, 256])
        
        return {
            "hue": hist_h.flatten(),
            "saturation": hist_s.flatten(),
            "value": hist_v.flatten()
        }
    
    def calculate_brightness(self, frame: np.ndarray) -> float:
        """计算帧亮度"""
        import cv2
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        return float(np.mean(gray))
    
    def calculate_contrast(self, frame: np.ndarray) -> float:
        """计算帧对比度"""
        import cv2
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        return float(np.std(gray))
    
    def detect_edges(self, frame: np.ndarray, threshold1: int = 50, threshold2: int = 150) -> np.ndarray:
        """检测边缘"""
        import cv2
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        edges = cv2.Canny(gray, threshold1, threshold2)
        return edges
    
    def calculate_motion_vectors(self, prev_frame: np.ndarray, curr_frame: np.ndarray) -> Dict[str, Any]:
        """计算运动向量"""
        import cv2

        # 转换为灰度图
        prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
        curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)

        try:
            # 使用稠密光流计算（Farneback方法）
            flow = cv2.calcOpticalFlowPyrLK(prev_gray, curr_gray, 0.5, 3, 15, 3, 5, 1.2, 0)

            if flow is not None:
                # 计算运动幅度
                magnitude = np.sqrt(flow[..., 0]**2 + flow[..., 1]**2)
                return {
                    "flow": flow,
                    "magnitude": magnitude,
                    "mean_magnitude": float(np.mean(magnitude))
                }
        except Exception:
            # 如果光流计算失败，使用简单的帧差
            diff = cv2.absdiff(prev_gray, curr_gray)
            mean_diff = float(np.mean(diff))
            return {"mean_magnitude": mean_diff / 255.0}

        return {"mean_magnitude": 0.0}


class SceneAnalyzer:
    """
    场景分析器基类
    
    用于检测场景变化和分割。
    """
    
    def __init__(self, threshold: float = 0.3):
        self.threshold = threshold
    
    def calculate_frame_difference(self, frame1: np.ndarray, frame2: np.ndarray) -> float:
        """计算两帧之间的差异"""
        import cv2
        
        # 转换为灰度图
        gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
        gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
        
        # 计算直方图
        hist1 = cv2.calcHist([gray1], [0], None, [256], [0, 256])
        hist2 = cv2.calcHist([gray2], [0], None, [256], [0, 256])
        
        # 计算直方图相关性
        correlation = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
        
        # 返回差异度（1 - 相关性）
        return 1.0 - correlation
    
    def detect_scene_changes(self, frames: List[np.ndarray], timestamps: List[float]) -> List[Dict[str, Any]]:
        """检测场景变化"""
        scenes = []
        scene_start = 0
        
        for i in range(1, len(frames)):
            diff = self.calculate_frame_difference(frames[i-1], frames[i])
            
            if diff > self.threshold:
                # 检测到场景变化
                scenes.append({
                    "start_time": timestamps[scene_start],
                    "end_time": timestamps[i-1],
                    "start_frame": scene_start,
                    "end_frame": i-1,
                    "duration": timestamps[i-1] - timestamps[scene_start],
                    "change_score": diff
                })
                scene_start = i
        
        # 添加最后一个场景
        if scene_start < len(frames) - 1:
            scenes.append({
                "start_time": timestamps[scene_start],
                "end_time": timestamps[-1],
                "start_frame": scene_start,
                "end_frame": len(frames) - 1,
                "duration": timestamps[-1] - timestamps[scene_start],
                "change_score": 0.0
            })
        
        return scenes


class AnalyzerFactory:
    """分析器工厂类"""
    
    _analyzers: Dict[str, type] = {}
    
    @classmethod
    def register(cls, name: str, analyzer_class: type) -> None:
        """注册分析器"""
        cls._analyzers[name] = analyzer_class
    
    @classmethod
    def create(cls, name: str, **kwargs) -> VideoAnalyzer:
        """创建分析器实例"""
        if name not in cls._analyzers:
            raise ValueError(f"未知的分析器类型: {name}")
        
        analyzer_class = cls._analyzers[name]
        return analyzer_class(**kwargs)
    
    @classmethod
    def list_analyzers(cls) -> List[str]:
        """列出所有注册的分析器"""
        return list(cls._analyzers.keys())


# 分析器装饰器
def analyzer(name: str):
    """分析器注册装饰器"""
    def decorator(cls):
        AnalyzerFactory.register(name, cls)
        return cls
    return decorator
